<template>
  <!-- 一种按深度绘制几何体的材质。深度基于相机远近平面。白色最近，黑色最远。 -->
  <!-- 深度材质有个特性，其外观不是由光照或某个材质属性决定的，而是由物体到相机的距离决定的，
通过这一个特性，我们可以创建出逐渐消失的效果，通常我们会利用相机的属性near和far来控制物体的消失速度，
如果near和far之间的差值非常大时，物体远离相机时消失的速度会很慢，相反当near和far之间的差值非常小，那么物体消失的速度就会很快-->
  <div class="mesh-depth">
    <div id="scene"></div>
    <div class="controls-box">
      <section>
        <el-row>
          <div v-for="(item, key) in properties" :key="key">
            <div v-if="item && item.name != undefined">
              <el-col :span="8">
                <span class="vertice-span">{{ item.name }}</span>
              </el-col>
              <el-col :span="13">
                <el-slider
                  v-model="item.value"
                  :min="item.min"
                  :max="item.max"
                  :step="item.step"
                  :format-tooltip="formatTooltip"
                ></el-slider>
              </el-col>
              <el-col :span="3">
                <span class="vertice-span">{{ item.value }}</span>
              </el-col>
            </div>
          </div>
        </el-row>
        <el-row>
          <el-button
            type="primary"
            class="controls-button"
            size="mini"
            @click="addCube"
            >addCube</el-button
          >
          <el-button
            type="primary"
            class="controls-button"
            size="mini"
            @click="removeCube"
            >removeCube</el-button
          >
        </el-row>
      </section>
    </div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

let scene;
let camera;
let renderer;
let controls;
export default {
  data() {
    return {
      properties: {
        near: {
          name: "near",
          value: 66,
          min: 0,
          max: 500,
          step: 1,
        },
        far: {
          name: "far",
          value: 230,
          min: 50,
          max: 1000,
          step: 1,
        },
        speed: {
          name: "speed",
          value: 0.02,
          min: 0,
          max: 0.5,
          step: 0.01,
        },
      },
      defaultCubeNum: 0,
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    formatTooltip(val) {
      return val;
    },

    // 初始化
    init() {
      this.createScene(); // 创建场景
      this.createLight(); // 创建光源
      this.createCamera(); // 创建相机
      this.createRender(); // 创建渲染器
      this.createControls(); // 创建控件对象
      this.render(); // 渲染
      this.initCube(); // 初始化方块
    },
    // 创建场景
    createScene() {
      scene = new THREE.Scene();
      scene.overrideMaterial = new THREE.MeshDepthMaterial();
    },

    // 创建光源
    createLight() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.1); // 创建环境光
      scene.add(ambientLight); // 将环境光添加到场景
    },
    // 创建相机
    createCamera() {
      const element = document.getElementById("scene");
      const k = element.clientWidth / element.clientHeight; // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      camera = new THREE.PerspectiveCamera(45, k, 20, 300);
      camera.position.set(80, 60, 80); // 设置相机位置
      camera.lookAt(new THREE.Vector3(0, 0, 0)); // 设置相机方向
      scene.add(camera);
    },
    initCube() {
      while (this.defaultCubeNum < 300) {
        this.addCube();
        this.defaultCubeNum++;
      }
    },
    removeCube() {
      const allChildren = scene.children;
      const lastObject = allChildren[allChildren.length - 1];
      if (lastObject instanceof THREE.Mesh) {
        scene.remove(lastObject);
      }
    },

    addCube() {
      const cubeSize = Math.ceil(3 + Math.random() * 3);
      const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);

      const cubeMaterial = new THREE.MeshLambertMaterial({
        color: 0xffffff,
      });

      this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

      this.cube.castShadow = true;
      this.cube.updateMatrix();

      // 设置方块位置
      this.cube.position.x = -50 + Math.round(Math.random() * 150);
      this.cube.position.y = Math.round(Math.random() * 10);
      this.cube.position.z = -150 + Math.round(Math.random() * 250);

      // 将方块添加到场景
      scene.add(this.cube);
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById("scene");
      renderer = new THREE.WebGLRenderer();
      renderer.setSize(element.clientWidth, element.clientHeight); // 设置渲染区域尺寸
      renderer.shadowMap.enabled = true; // 显示阴影
      renderer.setClearColor(0x000000, 1); // 设置背景颜色
      element.appendChild(renderer.domElement);
    },

    // 更新属性
    updateFun() {
      camera.near = this.properties.near.value;
      camera.far = this.properties.far.value;
      //在更新完相机的属性far和near后要调用camera.updateProjectionMatrix()
      camera.updateProjectionMatrix();
      const THIS = this;
      scene.traverse(function (e) {
        if (e instanceof THREE.Mesh) {
          e.rotation.x += THIS.properties.speed.value;
          e.rotation.y += THIS.properties.speed.value;
          e.rotation.z += THIS.properties.speed.value;
        }
      });
    },
    render() {
      this.updateFun();
      renderer.render(scene, camera);
      requestAnimationFrame(this.render);
    },
    // 创建控件对象
    createControls() {
      controls = new OrbitControls(camera, renderer.domElement);
      controls.target = new THREE.Vector3(0, 0, 0);
    },
  },
};
</script>

<style>
.mesh-depth {
  width: 100%;
  height: 100%;
  position: relative;
}
#scene {
  width: 100%;
  height: 100%;
}
.controls-box {
  position: absolute;
  right: 5px;
  top: 5px;
  width: 300px;
  padding: 10px;
  background-color: #fff;
  border: 1px solid #c3c3c3;
}
.label-col {
  padding: 8px 5px;
}
.color-select-layer {
  position: relative;
  left: -20px;
  padding: 15px 0;
}
.vertice-span {
  line-height: 38px;
  padding: 0 2px 0 10px;
}
</style>

